/*
 * This file is part of b.AMP.
 *
 * b.AMP is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * b.AMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "playback.hpp"
#include "control.hpp"
#include "console.hpp"
#include "config.hpp"

#include "pipeline/plugin_loader.hpp"
#include "service/message_channel.hpp"

#include <bamp/basic_message.hpp>

#include <boost/program_options.hpp>
#include <iostream>
#include <string>

namespace po = boost::program_options;


int main(int argc, char** argv)
{
    // Parse command-line arguments.
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h",   "show this help message")
        ("version,v", "show version information")
        ("config,c", po::value<std::string>(),
         "specify the configuration file to use")
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);    
    
    if (vm.count("help"))
    {
        std::cout << desc << std::endl;
        return 0;
    }

    if (vm.count("version"))
    {
        std::cout << BAMP_APP_NAME << " "
                  << BAMP_APP_VERSION << std::endl;
        return 0;
    }

    std::string configfile(BAMP_DEFAULT_CONFIG_FILE);
    if (vm.count("config"))
    {
        configfile = vm["config"].as<std::string>();
    }
    
    // Create the shared data structure that holds plugins.
    bamp::PluginLoader plugins;

    // Create the threads and connect everybody on a single channel.
    bamp::Control        control (plugins, configfile);
    bamp::Playback       playback(plugins);
    bamp::Console        console;
    bamp::MessageChannel channel;

    channel.addTarget(control);
    channel.addTarget(playback);
    channel.addTarget(console);
    control.setTarget(channel);
    playback.setTarget(channel);
    console.setTarget(channel);
    
    // Start the threads
    control.run();
    playback.run();
    console.run();

    // Forward stdin to the console
    std::string line;
    while (getline(std::cin, line) && console.isRunning())
    {
        bamp::BasicMessage msg("bamp::command");
        msg.setArg("cmd", line);
        console.send(msg);
    }

    channel.send(bamp::BasicMessage("bamp::exit"));

    // Wait until all threads have exited by themselves
    console.waitStop();
    playback.waitStop();
    control.waitStop();
}
